--  -------------------------------------------------------------------------
--  @Main: LiberAda
--
--  @Project: LiberAda
--  @Version: 1.0
--  @Created: 2009-10-01
--  @Author:  Markus Knauß, Ivan Bogicevic, Julian Trischler
--
--  @Description:
--    LiberAda generates HTML pages for ada source files. The ada source files
--    are parsed, internal documentation that is formatted according to the
--    "Richtlinie für die Programmierung in Ada (V5)" is formatted and linked
--    with pretty printed source code.
--  @Usage:
--    The command line for LiberAda accepts the following parameters:
--    +-i: Files and directories to include, e.g. test.adb ./src
--         (mandatory)
--    +-r: Recurse through the given directories
--         (optional, default: do not recurse)
--    +-o: Directory to which the generated documentation is written
--         (optional, default: ./)
--    +-ext: Extensions of source files that are parsed.
--           (optional, default: ads adb)
--    +-v: Verbose operation
--
--    An example for a command line:
--      liberada -i liberada.adb ./src -r -o ./doc -ext adb ads
--
--    Values to command line parameters are separated by a space character.
--    Keys indicating a command line parameter are preceded by '-'.
--
--  @Modifications:
--    +2011-11-23 JT: Fixed bug, so LiberAda won't crash anymore if a source
--      file cannot be read. LiberAda is terminated gracefully instead.
--    +2009-11-17 MK: Restructured the document model and the file
--      generation.
--  -------------------------------------------------------------------------
with Ada.Strings.Unbounded;
with Ada.Text_IO;
with Ada.Containers.Vectors;

with Ada_Tokenizer;

with Settings;
with Symbol;
with Symbol_Table;
with Document;
with Code_Parser;
with Errors;
with Comment_Parser;

--  -------------------------------------------------------------------------
--  @Procedure LiberAda
procedure LiberAda is

   package ASU renames Ada.Strings.Unbounded;

   --  The document object model (DOM) holds the data whereof the html
   --  destination files are build
   package Documents_Table is new Ada.Containers.Vectors
     (Index_Type => Natural,
      Element_Type => Document.Document_Type,
      "=" => Document."=");
   Documents : Documents_Table.Vector;

begin

   --  1. Evaluate the command line arguments and set the global
   --     state according to the elements.
   Settings.Read_From_Command_Line;
   if not Settings.Has_Source_Files then
      Errors.Print_Error (Errors.NO_SOURCE_FILES);
      return;
   end if;

   --  2. Parse all source files, generate the symbol table and
   --     generate the DOM.
   declare
      use Ada_Tokenizer;
      use ASU;
      use Symbol;

      --  Holds, whether the ada tokenizer could open the current source file
      OK : Boolean := False;

      --  Every found token is of a special kind (e.g. BEGIN_T, FOR_T, END_T)
      Kind : Ada_Tokenizer.Token_Type;

      --  The value of a token is its textual printing in the source code
      Value : ASU.Unbounded_String;

      --  The position of a token is also specified by its line number
      Line : Positive;

      --  While parsing the source code, the actual symbol is stored here
      Current_Symbol : Symbol.Symbol_Type;

      --  While going through all source files, its current doc. is stored here
      Current_Document : Document.Document_Type;

      --  Comment information
      Parsing_Comment : Boolean := False;

      --  The actually parsed comment.
      Comment : Comment_Parser.Comment_Type;
   begin
      --  We are interested in symbols (the other tokens are less interesting)
      --  Parse all source files
      for Files_Idx in Settings.Source_Files'Range loop
         if Settings.Verbose then
            Ada.Text_IO.New_Line;
            Ada.Text_IO.Put ("--- FILE: ------------------------------------");
            Ada.Text_IO.Put_Line ("---------------------------------------");
            Ada.Text_IO.Put_Line ("    " & ASU.To_String (
              Settings.Source_Files (Files_Idx)));
         end if;

         --  Try to open the current source file to get its tokens
         Ada_Tokenizer.Open_Input (ASU.To_String (
           Settings.Source_Files (Files_Idx)), OK);
         if OK then
            Current_Document.Initialize;
            Code_Parser.Set_Filepath (Settings.Source_Files (Files_Idx));
            Current_Document.Set_In_File (Settings.Source_Files (Files_Idx));

            --  Read the source file (token by token)
            while Ada_Tokenizer.Token_Available loop
               Ada_Tokenizer.Get_Token (Kind, Value, Line);
               if Settings.Verbose then
                  Ada.Text_IO.Put (ASU.To_String (Value));
                  Ada.Text_IO.Put ("[" & Kind'Img & "]");
               end if;

               --  Decide, whether to use the comment parser or the code parser
               if Kind = COMMENT_T and not Parsing_Comment then
                  --  Start a new comment section
                  Comment         := Comment_Parser.Start_Comment;
                  Parsing_Comment := True;
               elsif Kind = COMMENT_T and Parsing_Comment then
                  --  Continue parsing the comment
                  Comment.Add_Line (Value);
               else
                  --  If we are currently parsing a comment and there is a
                  --  token other than WHITESPACE_T and COMMENT_T then the
                  --  comment section is finished.
                  if Parsing_Comment and not (Kind = WHITESPACE_T) then
                     Current_Document.Add_Comment (Comment);
                     Comment.Finish_Comment;
                     Parsing_Comment := False;
                  end if;

                  --  The token is not a comment, so use the code parser
                  Current_Symbol := Code_Parser.Token_To_Symbol (Kind, Value);

                  --  Check, if the code parser generated a symbol of the token
                  if Current_Symbol.Get_Kind /= Symbol.EMPTY_T and
                     Current_Symbol.Get_Kind /= Symbol.UNKNOWN_T then

                     --  Add the symbol to the symbol table
                     Symbol_Table.Add_Symbol (Current_Symbol);

                     --  TODO FIXME: Add the symbol to the document
                     --  (perhaps unresolved)
                     --  Current_Document.Add_Symbol (Current_Symbol);
                  end if;
               end if;

               --  Write token to DOM
               Current_Document.Add_Token (Kind, Value);
            end loop;

            --  Add the whole html document to the DOM
            Documents.Append (Current_Document);
         else
            --  Failed to open the source file
            Errors.Print_Error (Errors.OPENING_SOURCE_FILE_FAILED);
            return;
         end if;
         Ada_Tokenizer.Close_Input;
      end loop;
   end;

   --  3. Resolve all symbols in the symbol table
   Symbol_Table.Resolve;

   --  4. Generate the HTML documentation for all files.
   declare
      Current_Document : Document.Document_Type;
      Documents_Cursor : Documents_Table.Cursor := Documents.First;
   begin
      while Documents_Table.Has_Element (Documents_Cursor) loop
         Current_Document := Documents_Table.Element (Documents_Cursor);
         Current_Document.Make_Table_Of_Contents;
         Current_Document.Write_HTML;
         Documents_Cursor := Documents_Table.Next (Documents_Cursor);
         Current_Document.Destroy;
      end loop;
   end;

end LiberAda;
